package com.demo.oauth.config;

import java.security.KeyPair;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import com.demo.oauth.component.JwtTokenEnhancer;
import com.demo.oauth.service.impl.SingleTokenServices;
import com.demo.oauth.service.impl.UserDetailServiceImpl;

import lombok.AllArgsConstructor;

/**
 * oauth2.0配置
 * 
 * @author jiange
 */
@AllArgsConstructor
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

	private final PasswordEncoder passwordEncoder;
	private final UserDetailServiceImpl userDetailsService;
	private final AuthenticationManager authenticationManager;
	private final JwtTokenEnhancer jwtTokenEnhancer;
    private final RedisTemplate<?, ?> redisTemplate;
    private final RedissonClient redissonClient;
	
    /**
     * 将令牌存在redis中，用于做单点登录
     */
	@Bean
    public TokenStore tokenStore() {
        return new RedisTokenStore(redisTemplate.getConnectionFactory());
    }

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory().withClient("test").secret(passwordEncoder.encode("123456")).scopes("all")
				.authorizedGrantTypes("password", "refresh_token", "authorization_code", "client_credentials")
				.accessTokenValiditySeconds(3600).refreshTokenValiditySeconds(86400);
//		clients.withClientDetails(clientDetails()); //这里是基于数据库的
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.authenticationManager(authenticationManager)
				 .userDetailsService(userDetailsService) // 配置加载用户信息的服务
				 .accessTokenConverter(accessTokenConverter())
				 .tokenStore(tokenStore())
				 .tokenServices(authorizationServerTokenServices());
		endpoints.exceptionTranslator(new MyWebResponseExceptionTranslator());
	}

	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		 security.tokenKeyAccess("permitAll()");
	     security.checkTokenAccess("isAuthenticated()");
	     security.allowFormAuthenticationForClients();
	}
	
	/**
	 * clientID存数据库时需要配置
	 * @return
	 */
//	@Bean
//    public ClientDetailsService clientDetails() {
//        return new JdbcClientDetailsService(dataSource);
//    }
	
//	@Bean
//	public TokenStore tokenStore() {
//		 return new JwtTokenStore(accessTokenConverter());
//	}

	@Bean
	public JwtAccessTokenConverter accessTokenConverter() {
		JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
		jwtAccessTokenConverter.setKeyPair(keyPair());
		return jwtAccessTokenConverter;
	}

	@Bean
	public KeyPair keyPair() {
		// 从classpath下的证书中获取秘钥对
		KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"),
				"123456".toCharArray());
		return keyStoreKeyFactory.getKeyPair("jwt", "123456".toCharArray());
	}
	
	/**
     * 该方法用户获取一个token服务对象（该对象描述了token有效期等信息）
     */
    private AuthorizationServerTokenServices authorizationServerTokenServices() {
        // 使用自定义实现
    	SingleTokenServices defaultTokenServices = new SingleTokenServices(redissonClient);
        defaultTokenServices.setReuseRefreshToken(false);
        defaultTokenServices.setSupportRefreshToken(true); // 是否开启令牌刷新
        defaultTokenServices.setTokenStore(tokenStore());

        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
		List<TokenEnhancer> delegates = new ArrayList<>();
		delegates.add(jwtTokenEnhancer);
		delegates.add(accessTokenConverter());
		enhancerChain.setTokenEnhancers(delegates); // 配置JWT的内容增强器
        // 针对jwt令牌的添加
        defaultTokenServices.setTokenEnhancer(enhancerChain);
//        defaultTokenServices.setClientDetailsService(clientDetails());


        return defaultTokenServices;
    }

}
